<template>
  <el-dialog
    title="录制语音"
    :visible.sync="visible"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :show-close="true"
    width="350px"
    @close="handleClose"
  >
    <!-- 录制状态显示 -->
    <div class="recording-status">
      <div
        class="recording-circle"
        :class="{
          recording: isRecording,
          paused: isPaused,
          warning: isRecordingOverMax,
        }"
      >
        <i :class="recordingIcon"></i>
      </div>

      <div class="recording-time">{{ recordingTimeFormatted }}</div>

      <div class="volume-wave" v-if="isRecording">
        <span
          v-for="(level, i) in volumeLevels"
          :key="i"
          :style="{ height: `${level}%` }"
          :class="{ 'volume-active': level > 0 }"
          class="volume-bar"
        ></span>
      </div>
    </div>

    <div class="status-message">
      {{ statusMessage }}
    </div>

    <div class="upload-progress" v-if="isUploading">
      <!-- 修复stroke-width属性的类型错误，使用数字类型 -->
      <el-progress :percentage="uploadProgress" :stroke-width="6"></el-progress>
      <div class="progress-text">{{ uploadProgress }}%</div>
    </div>

    <div class="mic-error-alert" v-if="showMicError">
      <div class="error-icon">⚠️</div>
      <div class="error-content">
        <h4>无法访问麦克风</h4>
        <p>{{ micErrorMsg }}</p>
        <el-button size="mini" @click="checkMicPermission" class="fix-btn"
          >尝试修复</el-button
        >
      </div>
    </div>

    <template #footer>
      <div class="control-buttons">
        <el-button
          type="text"
          @click="cancelRecording"
          :disabled="!isRecording && !isPaused && !isRecordingCompleted"
        >
          取消
        </el-button>

        <template v-if="!isRecordingCompleted">
          <!-- 录音中显示暂停和停止按钮 -->
          <template v-if="isRecording && !isPaused">
            <el-button type="warning" @click="pauseRecording"> 暂停 </el-button>
            <el-button type="danger" @click="stopRecording"> 停止 </el-button>
          </template>

          <!-- 暂停状态显示继续按钮 -->
          <template v-if="isPaused">
            <el-button type="primary" @click="resumeRecording">
              继续
            </el-button>
            <el-button type="danger" @click="stopRecording"> 停止 </el-button>
          </template>

          <!-- 未开始状态显示开始按钮 -->
          <template v-if="!isRecording && !isPaused">
            <el-button type="primary" @click="startRecording">
              开始录音
            </el-button>
          </template>
        </template>

        <el-button
          type="primary"
          @click="sendRecording"
          :disabled="!canSendRecording"
          :loading="isUploading"
        >
          <template v-if="!isUploading">发送</template>
          <template v-if="isUploading">上传中...</template>
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script>
import service from "../../utils/request";

class VoiceService {
  constructor(options = {}) {
    this.options = {
      maxDuration: 60,
      minDuration: 1,
      sampleRate: 44100,
      onDeviceError: null,
    };
    Object.assign(this.options, options);

    this.isSupported = this.checkSupport();
    this.mediaRecorder = null;
    this.audioContext = null;
    this.analyser = null;
    this.microphone = null;
    this.audioChunks = [];
    this.startTime = null;
    this.pauseTime = null;
    this.totalPausedTime = 0;
    this.volumeLevels = new Array(12).fill(0);
    this.volumeUpdateId = null;
    this.lastVolumeUpdate = 0;
    this.stream = null;
  }

  // 检查浏览器是否支持录音功能
  checkSupport() {
    return !!(
      navigator.mediaDevices &&
      navigator.mediaDevices.getUserMedia &&
      window.MediaRecorder &&
      window.AudioContext
    );
  }

  // 检测麦克风设备
  async detectMicDevice() {
    try {
      const devices = await navigator.mediaDevices.enumerateDevices();
      const audioInputs = devices.filter((d) => d.kind === "audioinput");
      return audioInputs.length > 0;
    } catch (error) {
      if (this.options.onDeviceError) {
        this.options.onDeviceError({
          name: error.name,
          message: "无法检测麦克风设备，请检查浏览器权限",
        });
      }
      return false;
    }
  }

  // 开始录音
  async start() {
    if (!this.isSupported) {
      throw new Error("您的浏览器不支持语音录制功能");
    }

    const hasMic = await this.detectMicDevice();
    if (!hasMic) {
      throw new Error("未检测到麦克风设备，请连接麦克风后重试");
    }

    try {
      if (!this.mediaRecorder || this.mediaRecorder.state === "inactive") {
        this.reset();

        this.stream = await navigator.mediaDevices.getUserMedia({
          audio: {
            echoCancellation: true,
            noiseSuppression: true,
            autoGainControl: true,
            sampleRate: this.options.sampleRate,
          },
        });

        this.audioContext = new AudioContext();
        this.analyser = this.audioContext.createAnalyser();
        this.analyser.fftSize = 128;
        this.analyser.smoothingTimeConstant = 0.3;
        this.microphone = this.audioContext.createMediaStreamSource(
          this.stream
        );
        this.microphone.connect(this.analyser);

        this.mediaRecorder = new MediaRecorder(this.stream);
        this.mediaRecorder.addEventListener("dataavailable", (event) => {
          this.audioChunks.push(event.data);
        });
      }

      if (this.mediaRecorder.state === "inactive") {
        this.mediaRecorder.start();
        this.startTime = Date.now();
      } else if (this.mediaRecorder.state === "paused") {
        this.mediaRecorder.resume();
        this.totalPausedTime += Date.now() - this.pauseTime;
        this.pauseTime = null;
      }

      this.startVolumeMonitoring();

      return { stream: this.stream, mediaRecorder: this.mediaRecorder };
    } catch (error) {
      if (this.options.onDeviceError) {
        this.options.onDeviceError(error);
      }
      throw error;
    }
  }

  // 暂停录音
  pause() {
    if (this.mediaRecorder && this.mediaRecorder.state === "recording") {
      this.mediaRecorder.pause();
      this.pauseTime = Date.now();
      this.stopVolumeMonitoring();
      return true;
    }
    return false;
  }

  // 音量监控逻辑
  startVolumeMonitoring() {
    this.stopVolumeMonitoring();

    if (!this.analyser) return;

    const bufferLength = this.analyser.frequencyBinCount;
    const dataArray = new Uint8Array(bufferLength);
    const updateInterval = 80;

    const updateVolume = (timestamp) => {
      if (
        !this.lastVolumeUpdate ||
        timestamp - this.lastVolumeUpdate > updateInterval
      ) {
        this.analyser.getByteFrequencyData(dataArray);

        const segmentSize = Math.floor(bufferLength / this.volumeLevels.length);
        const newLevels = [];

        for (let i = 0; i < this.volumeLevels.length; i++) {
          let sum = 0;
          let count = 0;

          for (let j = 0; j < segmentSize; j++) {
            const index = i * segmentSize + j;
            if (index < bufferLength) {
              sum += dataArray[index];
              count++;
            }
          }

          const average = sum / count;
          const gain = average < 30 ? 3 : average < 60 ? 2 : 1.2;
          const volume = Math.min(Math.max(Math.round(average * gain), 5), 100);

          const randomVariation = Math.floor(Math.random() * 5) - 2;
          newLevels.push(Math.max(5, volume + randomVariation));
        }

        this.volumeLevels = newLevels;
        this.lastVolumeUpdate = timestamp;
      }

      this.volumeUpdateId = requestAnimationFrame(updateVolume);
    };

    this.volumeUpdateId = requestAnimationFrame(updateVolume);
  }

  // 停止音量监控
  stopVolumeMonitoring() {
    if (this.volumeUpdateId) {
      cancelAnimationFrame(this.volumeUpdateId);
      this.volumeUpdateId = null;
    }
    this.lastVolumeUpdate = 0;
  }

  // 停止录音
  stop() {
    return new Promise((resolve) => {
      if (!this.mediaRecorder || this.mediaRecorder.state === "inactive") {
        resolve(null);
        return;
      }

      this.stopVolumeMonitoring();

      if (this.pauseTime) {
        this.totalPausedTime += Date.now() - this.pauseTime;
        this.pauseTime = null;
      }

      const duration = this.startTime
        ? (Date.now() - this.startTime - this.totalPausedTime) / 1000
        : 0;

      this.mediaRecorder.stop();
      this.mediaRecorder.addEventListener("stop", () => {
        if (this.stream) {
          this.stream.getTracks().forEach((track) => track.stop());
        }
        if (this.audioContext) {
          this.audioContext
            .close()
            .catch((e) => console.error("关闭音频上下文失败:", e));
        }

        const audioBlob =
          this.audioChunks.length > 0
            ? new Blob(this.audioChunks, { type: "audio/wav" })
            : null;

        resolve({ blob: audioBlob, duration });
      });
    });
  }

  // 重置录音状态
  reset() {
    this.stopVolumeMonitoring();

    if (this.mediaRecorder && this.mediaRecorder.state !== "inactive") {
      this.mediaRecorder.stop();
    }

    if (this.audioContext) {
      this.audioContext
        .close()
        .catch((e) => console.error("关闭音频上下文失败:", e));
    }

    if (this.stream) {
      this.stream.getTracks().forEach((track) => track.stop());
    }

    this.mediaRecorder = null;
    this.audioContext = null;
    this.analyser = null;
    this.microphone = null;
    this.stream = null;
    this.audioChunks = [];
    this.startTime = null;
    this.pauseTime = null;
    this.totalPausedTime = 0;
    this.volumeLevels = new Array(12).fill(0);
  }

  // 获取当前录音时长
  getCurrentDuration() {
    if (!this.startTime) return 0;

    let currentTime = Date.now();
    if (this.pauseTime) {
      currentTime = this.pauseTime;
    }

    return (currentTime - this.startTime - this.totalPausedTime) / 1000;
  }

  // 获取音量波形数据
  getVolumeLevels() {
    return [...this.volumeLevels];
  }
}

export default {
  name: "VoiceRecorder",
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    maxDuration: { type: Number, default: 60 },
    minDuration: { type: Number, default: 1 },
    maxFileSize: { type: Number, default: 50 },
  },
  data() {
    return {
      voiceService: null,
      isRecording: false,
      isPaused: false,
      isRecordingCompleted: false,
      isRecordingOverMax: false,
      isVoiceDisabled: false,
      isUploading: false,
      recordingBlob: null,
      recordingDuration: 0,
      recordingTime: 0,
      recordingTimer: null,
      volumeLevels: [],
      showMicError: false,
      micErrorMsg: "",
      uploadProgress: 0,
    };
  },
  computed: {
    recordingTimeFormatted() {
      const seconds = Math.floor(this.recordingTime);
      const minutes = Math.floor(seconds / 60);
      const remainingSeconds = seconds % 60;
      return `${minutes.toString().padStart(2, "0")}:${remainingSeconds
        .toString()
        .padStart(2, "0")}`;
    },

    recordingIcon() {
      if (!this.isRecording && !this.isPaused) {
        return "el-icon-video-play";
      } else if (this.isRecording && !this.isPaused) {
        return "el-icon-mic";
      } else {
        return "el-icon-pause";
      }
    },

    statusMessage() {
      if (this.isRecordingOverMax) {
        return `已达最大时长${this.maxDuration}秒`;
      } else if (this.isRecording && !this.isPaused) {
        return "正在录制...可暂停或直接停止录音";
      } else if (this.isPaused) {
        return "已暂停...可继续录音或停止";
      } else if (this.isRecordingCompleted) {
        return `录音已完成，时长${this.recordingTimeFormatted}`;
      } else {
        return "点击开始按钮开始录音";
      }
    },

    // 控制发送按钮状态
    canSendRecording() {
      return (
        this.isRecordingCompleted &&
        !this.isUploading &&
        !!this.recordingBlob &&
        this.recordingDuration >= this.minDuration
      );
    },
  },
  watch: {
    recordingTime(val) {
      if (val >= this.maxDuration && this.isRecording && !this.isPaused) {
        this.isRecordingOverMax = true;
        this.stopRecording();
      }
    },
    visible(newVal) {
      if (newVal) {
        this.initVoiceService();
        this.detectMicDevice();
      } else {
        if (this.isRecording || this.isPaused) {
          this.stopRecording();
        }
        this.resetRecordingState();
      }
    },
  },
  methods: {
    initVoiceService() {
      if (!this.voiceService) {
        this.voiceService = new VoiceService({
          maxDuration: this.maxDuration,
          minDuration: this.minDuration,
          onDeviceError: (error) => {
            this.showMicError = true;
            if (error.name === "NotFoundError") {
              this.micErrorMsg = "未找到麦克风设备，请连接麦克风后重试。";
            } else if (
              error.name === "NotAllowedError" ||
              error.name === "PermissionDeniedError"
            ) {
              this.micErrorMsg =
                "浏览器未获得麦克风权限，请在浏览器设置中开启。";
            } else if (error.name === "NotSupportedError") {
              this.micErrorMsg = "您的浏览器不支持语音录制功能，请更换浏览器。";
            } else {
              this.micErrorMsg = `麦克风错误: ${error.message || "未知错误"}`;
            }
          },
        });
        this.isVoiceDisabled = !this.voiceService.isSupported;
      }
    },

    async detectMicDevice() {
      this.initVoiceService();
      const hasMic = await this.voiceService.detectMicDevice();
      if (!hasMic) {
        this.showMicError = true;
        this.micErrorMsg = "未检测到麦克风设备，请连接麦克风后重试。";
        return false;
      }
      return true;
    },

    async checkMicPermission() {
      try {
        this.showMicError = false;
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: true,
        });
        stream.getTracks().forEach((track) => track.stop());
        this.isVoiceDisabled = false;
        this.$message.success("麦克风权限已获取，可正常录音");
        return true;
      } catch (error) {
        this.voiceService.options.onDeviceError(error);
        return false;
      }
    },

    handleClose() {
      this.$emit("update:visible", false);
    },

    async startRecording() {
      if (!this.voiceService) {
        this.initVoiceService();
      }

      try {
        this.isRecording = true;
        this.isPaused = false;
        this.isRecordingCompleted = false;
        this.isRecordingOverMax = false;

        await this.voiceService.start();

        this.startRecordingTimer();
      } catch (error) {
        this.$message.error(error.message || "操作失败，请重试");
        this.resetRecordingState();
      }
    },

    pauseRecording() {
      if (this.voiceService.pause()) {
        this.isRecording = false;
        this.isPaused = true;
        this.stopRecordingTimer();
      }
    },

    async resumeRecording() {
      try {
        this.isRecording = true;
        this.isPaused = false;

        await this.voiceService.start();

        this.startRecordingTimer();
      } catch (error) {
        this.$message.error(error.message || "操作失败，请重试");
      }
    },

    async stopRecording() {
      if (this.isRecordingCompleted) return;

      this.isRecording = false;
      this.isPaused = false;
      this.isRecordingCompleted = true;

      this.stopRecordingTimer();

      try {
        const result = await this.voiceService.stop();
        if (result && result.blob) {
          this.recordingBlob = result.blob;
          this.recordingDuration = result.duration;
          this.recordingTime = result.duration;

          if (this.recordingDuration < this.minDuration) {
            this.$message.warning(
              `录音时间太短，请至少录制${this.minDuration}秒`
            );
          }

          if (
            this.maxFileSize &&
            result.blob.size > this.maxFileSize * 1024 * 1024
          ) {
            this.$message.warning(`文件大小超过${this.maxFileSize}MB限制`);
          }
        } else {
          this.isRecordingCompleted = false;
          this.$message.error("未获取到录音数据，请重试");
        }
      } catch (error) {
        this.isRecordingCompleted = false;
        this.$message.error("录音处理失败，请重试");
        console.error("录音停止错误:", error);
      }
    },

    cancelRecording() {
      this.stopRecordingTimer();
      if (this.voiceService) {
        this.voiceService.reset();
      }
      this.resetRecordingState();
    },

    async sendRecording() {
      if (!this.canSendRecording) return;

      try {
        this.isUploading = true;
        this.uploadProgress = 0;

        const formData = new FormData();
        const fileName = `voice_${Date.now()}.wav`;

        // 创建语音文件
        const voiceFile = new File([this.recordingBlob], fileName, {
          type: "audio/wav",
        });
        formData.append("file", voiceFile);
        formData.append("duration", Math.round(this.recordingDuration));

        // 使用完整配置的请求方式
        const res = await service({
          method: "post",
          url: "/upload/voice",
          data: formData, // 直接传递FormData对象
          onUploadProgress: (progressEvent) => {
            if (progressEvent.lengthComputable) {
              this.uploadProgress = Math.round(
                (progressEvent.loaded / progressEvent.total) * 100
              );
            }
          },
          timeout: 60000,
        });

        if (res.code === 200) {
        //   this.$message.success("语音消息发送成功");
          this.$emit("voice-sent", {
            url: res.data,
            duration: this.recordingDuration,
            fileName: fileName,
          });
          this.$emit("update:visible", false);
        } else {
          throw new Error(res.message || "语音上传失败");
        }
      } catch (error) {
        // this.$message.error("语音发送失败，请重试");
        console.error("语音上传错误:", error);
      } finally {
        this.isUploading = false;
        this.uploadProgress = 0;
      }
    },

    //图片上传 - 使用原有service接口
    async uploadImage(message) {
      try {
        message.uploading = true;
        const formData = new FormData();
        formData.append('file', message.content.file);
        
        // 使用项目原有的service接口上传图片
        const response = await service.upload('/api/upload/image', formData, {
          onUploadProgress: (progressEvent) => {
            // 计算上传进度百分比
            message.uploadProgress = Math.round(
              (progressEvent.loaded / progressEvent.total) * 100
            );
          }
        });
        
        // 上传成功后更新图片URL为服务器地址
        message.content.url = response.data.url;
        message.content.fileId = response.data.fileId;
        message.uploading = false;
        
        // 可以在这里添加消息发送到聊天服务器的逻辑
        // await this.sendMessageToServer(message);
      } catch (error) {
        console.error('图片上传失败:', error);
        message.uploading = false;
        this.$message.error('图片上传失败，请重试');
      }
    },
    startRecordingTimer() {
      if (this.recordingTimer) {
        clearInterval(this.recordingTimer);
      }

      this.recordingTimer = setInterval(() => {
        this.recordingTime = this.voiceService.getCurrentDuration();
        this.volumeLevels = [...this.voiceService.getVolumeLevels()];
      }, 50);
    },

    stopRecordingTimer() {
      if (this.recordingTimer) {
        clearInterval(this.recordingTimer);
        this.recordingTimer = null;
      }
    },

    resetRecordingState() {
      this.stopRecordingTimer();

      this.isRecording = false;
      this.isPaused = false;
      this.isRecordingCompleted = false;
      this.isRecordingOverMax = false;

      this.recordingBlob = null;
      this.recordingDuration = 0;
      this.recordingTime = 0;
      this.volumeLevels = [];

      if (this.voiceService) {
        this.voiceService.reset();
      }
    },
  },
  mounted() {
    this.initVoiceService();
  },
  beforeDestroy() {
    this.stopRecordingTimer();
    if (this.voiceService) {
      this.voiceService.reset();
    }
  },
};
</script>

<style scoped>
.recording-status {
  padding: 20px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.recording-circle {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background-color: #f5f5f5;
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
  position: relative;
  font-size: 30px;
}

.recording-circle.recording {
  background-color: #ff4d4f;
  box-shadow: 0 0 20px rgba(255, 77, 79, 0.4);
  color: white;
  animation: pulse 1.5s infinite;
}

.recording-circle.paused {
  background-color: #faad14;
  box-shadow: 0 0 20px rgba(250, 173, 20, 0.3);
  color: white;
}

.recording-circle.warning {
  animation: warning 1s infinite alternate;
}

.recording-time {
  font-size: 24px;
  font-weight: 600;
  color: #333;
  margin-bottom: 15px;
}

.volume-wave {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  height: 50px;
  width: 100%;
  max-width: 220px;
}

.volume-bar {
  display: inline-block;
  width: 3px;
  background-color: #1890ff;
  border-radius: 2px;
  transition: height 0.08s ease-out;
  opacity: 0.3;
}

.volume-bar.volume-active {
  opacity: 1;
}

.status-message {
  padding: 0 20px 15px;
  text-align: center;
  color: #666;
  font-size: 14px;
  min-height: 20px;
}

.control-buttons {
  display: flex;
  gap: 10px;
  width: 100%;
  justify-content: flex-end;
}

.upload-progress {
  padding: 0 0 15px;
}

.progress-text {
  text-align: right;
  font-size: 12px;
  color: #666;
  margin-top: 5px;
}

.mic-error-alert {
  margin-top: 15px;
  padding: 12px;
  background-color: #fff1f0;
  border: 1px solid #ffa39e;
  border-radius: 8px;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  color: #cf1322;
}

.error-icon {
  font-size: 18px;
  margin-top: 1px;
}

.error-content {
  flex: 1;
}

.error-content h4 {
  font-size: 14px;
  margin: 0 0 5px;
  font-weight: 600;
}

.error-content p {
  font-size: 13px;
  margin: 0 0 8px;
  line-height: 1.4;
}

.fix-btn {
  background-color: #ff4d4f !important;
  color: white !important;
}

@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(255, 77, 79, 0.4);
  }
  70% {
    box-shadow: 0 0 0 10px rgba(255, 77, 79, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(255, 77, 79, 0);
  }
}

@keyframes warning {
  from {
    box-shadow: 0 0 0 0 rgba(250, 173, 20, 0.7);
  }
  to {
    box-shadow: 0 0 0 10px rgba(250, 173, 20, 0.4);
  }
}
</style>
    